#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/errno.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/sem.h>
#include <errno.h>

#define MAXSIZE 32
#define NO (-1)

union semun{
    int val;
};

void delete(char* ch,int shmid,int semid){
    if(ch != NULL){
        if (shmdt(ch) == -1){ // 取消映射
            printf("shmdt err\n");
        }
    }

    if(shmid > 0){
        if (shmctl(shmid, IPC_RMID, NULL) == -1){ // 删除共享内存
            printf("shmctl err\n");
        }
    }

    if(semid > 0){
        if(semctl(semid,0,IPC_RMID) == -1){//删除信号灯集
            printf("semctl err\n");
        }
    }

}


int operate(struct sembuf *buf, int num, int op, int flg,int semid){
    (*buf).sem_num = num;       // 信号灯编号
    (*buf).sem_op = op;       // 申请资源
    (*buf).sem_flg = flg;       // 阻塞
    // 对0号灯作申请资源
    if(semop(semid, buf, 1) < 0){
        return -1;
    }
    return 0;
}


int main(int argc,const char*  argv[]){

    key_t key = ftok("./app",'a');
    if(key < 0){
        perror("ftok err");
        return -1;
    }
    printf("key:%#x\n",key);



    int shmid = shmget(key,MAXSIZE,IPC_CREAT | IPC_EXCL | 0666);
    if(shmid <= 0){
        if(errno == EEXIST){
            shmid = shmget(key,MAXSIZE,0666);
        }else{
            perror("shmget err");
            return -1;
        }
    }

    printf("shmid:%d\n",shmid);


    char* input=(void*)shmat(shmid,NULL,0);
    if(input == (char*)-1){
        perror("shmat err");
        delete(NULL,shmid,NO);
        return -1;
    }
    memset(input,0,MAXSIZE);

    //信号灯集

    int semid = semget(key,1,IPC_CREAT | IPC_EXCL | 0666);
    if(semid <= 0){
        if(errno == EEXIST){
            semid = semget(key,1,0666);
        }else{
            perror("semget err");
            delete(input,shmid,NO);
            return -1;
        }
    }else{
        union semun sem;
        sem.val=1;//设置资源量
        semctl(semid,0,SETVAL,sem);
        if(semctl(semid, 0, SETVAL, sem) == -1){
            delete(input,shmid,semid);
            return -1;
        }
    }
    struct sembuf buf;
    while(1){
            
        if(operate(&buf,0,-1,0,semid) == -1){//申请资源
            break;
        }

        if(strcmp(input,"quit") == 0){
            break;
        }

        printf("输出:%s\n",input);
        
        if(operate(&buf,0,1,0,semid) == -1){//释放资源
            break;
        }

    }

    delete(input,NO,NO);

    return 0;
}